﻿using System;
using System.Collections.Generic;
using System.IO;
using iStudio.Structure.Project;
using iStudio.Structure.Wave;

namespace iStudio.Format
{
    public abstract class Format
    {
        private readonly List<FormatDescriptor> _supportedFormats;
 
        protected Format ()
        {
            _supportedFormats = new List<FormatDescriptor> ();
        }

        protected void RegisterFormat(FormatType type, FormatSupport support)
        {
            FormatDescriptor format = new FormatDescriptor
            {
                Type = type,
                Support = support
            };

            _supportedFormats.Add(format);
        }

        public string Name
        {
            get;
            protected set;
        }

        public List<FormatDescriptor> GetSupportedFileFormats()
        {
            return new List<FormatDescriptor> (_supportedFormats);
        }

        public List<FormatDescriptor> GetSupportedFileFormats(FormatSupport support)
        {
            List<FormatDescriptor> supported = new List<FormatDescriptor> ();

            foreach (FormatDescriptor format in _supportedFormats)
            {
                if ((format.Support == support) || (format.Support == FormatSupport.Complete))
                {
                    supported.Add(format);
                }
            }

            return supported;
        }

        public bool SupportsFileFormat(FormatType type, FormatSupport support)
        {
            foreach (FormatDescriptor format in _supportedFormats)
            {
                if ( (format.Type == type) && ( (format.Support == support) || (format.Support == FormatSupport.Complete) ) )
                {
                    return true;
                }
            }

            return false;
        }

        public void Export(string file, FormatType type, WaveProject project)
        {
            if (SupportsFileFormat (type, FormatSupport.CanSave))
            {
                ExecuteExport (file, type, project);
            }

            throw new NotSupportedException("Exporting is not supported in selected format");
        }

        public List<WaveTrack> Import (string file)
        {
            if (SupportsFileFormat (GetFormatType (file), FormatSupport.CanOpen))
            {
                return ExecuteImport (file);
            }

            throw new NotSupportedException("Importing is not supported in selected format");
        }

        protected virtual void ExecuteExport(string file, FormatType type, WaveProject tracks)
        {
            throw new NotSupportedException("Exporting is not supported in selected format.");
        }

        protected virtual List<WaveTrack> ExecuteImport (string file)
        {
            throw new NotSupportedException("Importing is not supported in selected format");
        }

        protected abstract List<WaveTrack> OpenStream (Stream stream);

        /// <summary>
        /// Method creates filter string from supported formats
        /// </summary>
        /// <param name="supportedFormats">supported format list </param>
        /// <param name="open">true if you need open filter </param>
        /// <returns>filter string</returns>
        public static string CreateFilterString(IEnumerable<FormatDescriptor> supportedFormats, bool open = true)
        {
            string fileFilter = "";
            string filters = "";

            //
            // Construct supported files
            //

            foreach (FormatDescriptor formatDescriptor in supportedFormats)
            {
                switch (formatDescriptor.Type)
                {
                    case FormatType.Mp3:
                        fileFilter += "*.mp3;";
                        filters += "MP3 files (*.mp3)|*.mp3|";

                        break;
                    case FormatType.Wav:
                        fileFilter += "*.wav;";
                        filters += "WAVE files (*.wav)|*.wav|";

                        break;
                    case FormatType.Wma:
                        fileFilter += "*.wma;";
                        filters += "Windows Media Audio files (*.wma)|*.wma|";

                        break;
                    case FormatType.Aiff:
                        fileFilter += "*.aiff;";
                        filters += "AIFF files (*.aiff)|*.aiff|";

                        break;
                }
            }

            // Verify formats
            if ( (filters.Length > 0) && (fileFilter.Length > 0) )
            {

                //
                // Cut away list semicolon and |
                //
                fileFilter = fileFilter.Substring (0, fileFilter.Length - 1);
                filters = filters.Substring (0, filters.Length - 1);

                //
                // Include all supported files and all files for open
                //

                if (open)
                {
                    return "All media files (" + fileFilter.Replace (";", ", ") + ")|" + fileFilter + "|" + filters + "|All files|*.*";
                }

                return filters;
            }

            return null;    
        }

        /// <summary>
        /// Returns format type from filename
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static FormatType GetFormatType (string file)
        {
            string extension = Path.GetExtension (file);

            switch (extension)
            {
                case ".wav":
                    return FormatType.Wav;
                case ".mp3":
                    return FormatType.Mp3;
                case ".aiff":
                    return FormatType.Aiff;
                case ".ogg":
                    return FormatType.Ogg;
                case ".wma":
                    return FormatType.Wma;
            }

            return FormatType.Wav;
        }
    }
}
